#include "player_controls.h"
#include "../../images_manager.h"

#include "math.h"

#include <QRadialGradient>

int PlayerControls::CTRL_PREV_SEGMENT = 0;
int PlayerControls::CTRL_PLAY = 1;
int PlayerControls::CTRL_STOP = 2;
int PlayerControls::CTRL_NEXT_SEGMENT = 3;
int PlayerControls::CTRL_PAUSE = 4;

PlayerControls::PlayerControls(Widget* _parent, Engine* _engine, int _x, int _y, int _w, int _h)
    :Widget( _parent, _engine, _x, _y, _w, _h ),
    stopAnime( _engine->fps, 400 ),
    prevAnime( _engine->fps, 400 ),
    playAnime( _engine->fps, 400 ),
    nextAnime( _engine->fps, 400 )
{
    DrawCloud();

    QRadialGradient rGradient( QPointF( w/2, h/2 ), h/2 );
    rGradient.setColorAt( 0, QColor( 255, 255, 255, 255 ) );
    rGradient.setColorAt( 1, QColor( 255, 200, 0, 200 ) );
    cloudBrush = new QBrush( rGradient );
    cloudGradient = ( QRadialGradient* )cloudBrush->gradient();

    selectionBrush = new QBrush( QColor( 255, 0, 0, 70 ), Qt::SolidPattern );
    pressedBrush = new QBrush( QColor( 255, 0, 0, 200 ), Qt::SolidPattern );

    // draws the stop pixmap
    QBrush controlsBrush( QColor( 0, 0, 0, 255 ), Qt::SolidPattern );
    stopPixmap = new QPixmap( 40, 40 );
    stopPixmap->fill( QColor( 255, 255, 255, 0 ) );
    QPainter p( stopPixmap );
    p.setBrush( controlsBrush );
    p.drawRect( 0, 0, 40, 40 );

    // draws the play pixmap
    playPixmap = new QPixmap( 40, 40 );
    playPixmap->fill( QColor( 255, 255, 255, 0 ) );
    QPainter p1( playPixmap );
    QPointF vertex[3] = { QPointF( 0, 0 ),  QPointF( 0, 40 ), QPointF( 40, 20 ) };
    p1.setBrush( controlsBrush );
    p1.drawPolygon( vertex, 3 );
    p1.end();

    // draws the pause pixmap
    pausePixmap = new QPixmap( 40, 40 );
    pausePixmap->fill( QColor( 0, 0, 0, 0 ) );
    QPainter p4( pausePixmap );
    p4.setBrush( controlsBrush );
    p4.drawRect( 0, 0, 15, 40 );
    p4.drawRect( 24, 0, 15, 40 );
    p4.end();

    // draws the next segment pixmap
    nextSegmentPixmap = new QPixmap( 40, 40 );
    nextSegmentPixmap->fill( QColor( 255, 255, 255, 0 ) );
    QPainter p2( nextSegmentPixmap );
    p2.drawPixmap( 0, 0, 20, 40, *playPixmap, 0, 0, 40, 40 );
    p2.drawPixmap( 20, 0, 20, 40, *playPixmap, 0, 0, 40, 40 );
    p2.end();

    // draws the prev segment pixmap
    prevSegmentPixmap = new QPixmap( 40, 40 );
    prevSegmentPixmap->fill( QColor( 255, 255, 255, 0 ) );
    QPainter p3( prevSegmentPixmap );
    p3.rotate( 180 );
    p3.drawPixmap( -40, -40, *nextSegmentPixmap, 0, 0, 40, 40 );
    p3.end();

    h2 = h/2;
    w6 = w/6;
    InitializeVolumeStuff();

    int w2 = w/2, w3 = w/3, w5 = w/5, w10 = w/10;
    stopX = w3 + w10;
    stopOffset = 10;

    playX = w6 + w10;
    playOffset = 10;

    nextX = w2 + w10;
    nextOffset = 10;

    prevX = w10;
    prevOffset = 10;

    prevRect = new QRect( 0, 0, w5, h );
    playRect = new QRect( w6, 0, w5, h );
    stopRect = new QRect( w3, 0, w5, h );
    nextRect = new QRect( w2, 0, w5, h );
    volRect = new QRect( w - w5 * 1.7, 0, 1.7 * w5, h );
    rectArray[0] = prevRect;
    rectArray[1] = playRect;
    rectArray[2] = stopRect;
    rectArray[3] = nextRect;
    rectArray[4] = volRect;

    // builds the animations
    animeGraph.AddSimpleProperty( "stopOffset", stopOffset );
    animeGraph.AddInterpolator( stopAnime.GetTime(), 0, 400, "stopOffset", 10, 16 );

    animeGraph.AddSimpleProperty( "playOffset", playOffset );
    animeGraph.AddInterpolator( playAnime.GetTime(), 0, 400, "playOffset", 10, 16 );

    animeGraph.AddSimpleProperty( "prevOffset", prevOffset );
    animeGraph.AddInterpolator( prevAnime.GetTime(), 0, 400, "prevOffset", 10, 16 );

    animeGraph.AddSimpleProperty( "nextOffset", nextOffset );
    animeGraph.AddInterpolator( nextAnime.GetTime(), 0, 400, "nextOffset", 10, 16 );

    stopAnime.AddObserver( this );
    engine->AddAnimation( &stopAnime );
    playAnime.AddObserver( this );
    engine->AddAnimation( &playAnime );
    prevAnime.AddObserver( this );
    engine->AddAnimation( &prevAnime );
    nextAnime.AddObserver( this );
    engine->AddAnimation( &nextAnime );

    animeArray[0] = &prevAnime;
    animeArray[1] = &playAnime;
    animeArray[2] = &stopAnime;
    animeArray[3] = &nextAnime;

    playing = false;
    controlSelected = -1;
    controlPressed = -1;

    mouseTracking = true;
}

void PlayerControls::InitializeVolumeStuff()
{
    // volume image pixmap
    volImgPixmap = new QPixmap( 30, 30 );
    volImgPixmap->fill( QColor( 255, 255, 255, 0 ) );
    QImage* volImg = ImagesManager::GetInstance()->GetImage( ImagesManager::VOLUME );
    QPainter volPainter( volImgPixmap );
    volPainter.drawImage( QRect( 0, 0, 30, 30 ), *volImg, QRect( 0, 0, volImg->width(), volImg->height() ) );
    volPainter.end();

    int w5 = w/5;
    volX = w - 1.5*w5;

    // volume triangle
    volSliderRect = new QRect( volX + 35, h2 - 15, w/6, 30 );

    volPixmap = new QPixmap( w/6, 31 );
    volPixmap->fill( QColor( 0, 0, 0, 0) );

    QLinearGradient lg( 0, 15, volSliderRect->width(), 15 );
    lg.setColorAt( 0, Qt::green );
    lg.setColorAt( 1, Qt::red );
    QBrush vBrush( lg );
    QPainter volPixmapPainter( volPixmap );
    QPointF tPoints[3] = { QPointF( 0, 30 ), QPointF( volPixmap->width(), 0 ), QPointF( volPixmap->width(), 30 ) };
    volPixmapPainter.setPen( Qt::NoPen );
    volPixmapPainter.setBrush( vBrush );
    volPixmapPainter.drawPolygon( tPoints, 3 );
    volPixmapPainter.end();

    QPolygonF tPol;
    tPol << tPoints[0] << tPoints[1] << tPoints[2];
    volPath.addPolygon( tPol );
    volPath.closeSubpath();

    m = -(float)30 / w6;
    volPos = 0.5;

    backTriangleBrush = new QBrush( QColor( 255, 255, 255, 50 ), Qt::SolidPattern );

    volDragging = false;
    prevVolX = 0;
}

PlayerControls::~PlayerControls()
{
    delete backTriangleBrush;
    delete volPixmap;
    delete volRect;
    delete volImgPixmap;
    delete pressedBrush;
    delete selectionBrush;
    delete prevRect;
    delete playRect;
    delete stopRect;
    delete nextRect;
    delete volRect;
    delete stopPixmap;
    delete playPixmap;
    delete nextSegmentPixmap;
    delete prevSegmentPixmap;
    delete cloudBrush;
}

void PlayerControls::Paint( QPainter& painter )
{
    painter.translate( x, y );

    // draws the selection first
    if( controlSelected != -1 )
    {
        painter.setPen( Qt::NoPen );

        if( controlSelected == controlPressed )
        {
            painter.setBrush( *pressedBrush );
        }
        else
        {
            painter.setBrush( *selectionBrush );
        }
        painter.drawEllipse( *( rectArray[ controlSelected ] ) );
    }

    // then the cloud
    painter.setBrush( *cloudBrush );
    painter.setPen( Qt::black );
    painter.drawPath( cloud );

    // draws the commands
    DrawControl( painter, *stopPixmap, stopX, stopOffset );
    DrawControl( painter, *nextSegmentPixmap, nextX, nextOffset);
    DrawControl( painter, *prevSegmentPixmap, prevX, prevOffset );
    DrawControl( painter, playing? *pausePixmap: *playPixmap, playX, playOffset );

    // draws the volume command
    painter.drawPixmap( volX, h2 - 15, *volImgPixmap, 0, 0, 30, 30 );
    painter.translate( volSliderRect->x(), volSliderRect->y() );
    painter.setBrush( *backTriangleBrush );
    painter.drawPath( volPath );
    int offset = volPos * w6;
    painter.drawPixmap( 0, 0, *volPixmap, 0, 0, offset, 30 );
    painter.translate( -volSliderRect->x(), -volSliderRect->y() );
    painter.drawText( volSliderRect->x() + 5, volSliderRect->y() + 10, QString::number( (int)(volPos * 100) ) + "%" );

    painter.translate( -x, -y );
}

void PlayerControls::Init( void )
{
    playing = false;
    controlSelected = -1;
    controlPressed = -1;
    volPos = 0.5;
}

void PlayerControls::AddPlayerControlsListener( PlayerControlsListener* pcl )
{
    listeners.append( pcl );
}

void PlayerControls::DrawControl( QPainter& p, QPixmap& pixmap, int& x, int& offset )
{
    p.drawPixmap( x - offset, h2 - offset, 2 * offset, 2 * offset, pixmap, 0, 0, 40, 40 );
}

// mouse handling
void PlayerControls::OnMousePressed( QMouseEvent *e, bool inside, int x_rel, int y_rel )
{
    if( inside )
    {

        controlPressed = controlSelected;

        if( volSliderRect->contains( x_rel, y_rel, true ) )
        {
            // triangle test
            float tmpx = x_rel - volSliderRect->x();
            int tmp = ( tmpx - w6 ) * m;

            if ( tmp < ( y_rel - volSliderRect->y() ) )
            {
                volPos = tmpx/w6;
                TriggerEvent( true );

                volDragging = true;
                prevVolX = x_rel;
                prevVolPos = volPos;
            }
        }
    }
}

void PlayerControls::OnMouseReleased( QMouseEvent *e, bool inside, int x_rel, int y_rel )
{
    if( inside )
    {
        if( controlPressed == controlSelected && controlSelected != 4 )
        {
            if( controlPressed == 1 )
            {
                playing = !playing;
            }
            else if( controlPressed == 2 )
            {
                playing = false;
            }
            TriggerEvent( false );
        }
        controlPressed = -1;
    }
    else
    {
        controlPressed = -1;
    }
    volDragging = false;
}

void PlayerControls::OnMouseMoved( QMouseEvent *e, bool onWidget, int x_rel, int y_rel )
{
    if( onWidget )
    {
        cloudGradient->setCenter( x_rel, y_rel );
        cloudGradient->setFocalPoint( x_rel, y_rel );

        bool ok = false;

        for( int i=0; i<4; i++ )
        {
            if( rectArray[i]->contains( x_rel, y_rel, true ) )
            {
                controlSelected = i;

                if( !animeArray[i]->IsRunning() )
                {
                    animeArray[i]->Play();
                }
                ok = true;
                break;
            }
        }

        if( !ok )
        {
            controlSelected = 4;
        }

        if( volDragging )
        {
            int offset = x_rel - prevVolX;
            volPos = prevVolPos + (float)offset/w6;
            if ( volPos < 0 ) volPos = 0;
            if ( volPos > 1 ) volPos = 1;
            TriggerEvent( true );
        }
    } else
    {
        controlSelected = -1;
    }
}


void PlayerControls::DrawCloud()
{
    int smallCloudWidth = w/5;
    int cloudOffset = w/6;
    smallSelection.addEllipse( 0, 0, smallCloudWidth, h );

    for( int i=0; i<4; i++ )
    {
        cloud += smallSelection;
        smallSelection.translate( cloudOffset, 0 );
    }
    smallSelection.translate( -4 * cloudOffset, 0 );

    bigSelection.addEllipse( 0, 0, 1.7 * smallCloudWidth, h );
    bigSelection.translate( w - 1.7 * smallCloudWidth, 0 );
    cloud += bigSelection;
}

// AnimationListener implementation
void PlayerControls::OnPause( Animation* a ){}
void PlayerControls::OnStop( Animation* a ){}
void PlayerControls::OnEnd( Animation* a )
{
    int ctrl = -1;
    if( a == &prevAnime )
    {
        ctrl = 0;
    }
    else if( a == &playAnime )
    {
        ctrl = 1;
    }
    else if( a == &stopAnime )
    {
        ctrl = 2;
    }
    else
    {
        ctrl = 3;
    }

    if( !a->IsReversed() )
    {
        a->Reverse();
        a->Play();
    }
    else
    {
        a->Reverse();

        if( controlSelected == ctrl )
        {
            a->Play();
        }
    }
}

void PlayerControls::OnPlay(Animation* a){}

void PlayerControls::TriggerEvent( bool vol )
{
    if( !vol )
    {
        int ctrl = controlSelected;
        if( ctrl == 1 && !playing ) ctrl = 4;
        for( int i=0; i<listeners.size(); i++ )
        {
            listeners.at(i)->OnControlClick( this, ctrl );
        }
    }
    else
    {
        for( int i=0; i<listeners.size(); i++ )
        {
            listeners.at(i)->OnVolumeChange( this, volPos );
        }
    }
}
